package cn.edu.zstu.qingzhu.qingzhushop.service.impl;

import cn.edu.zstu.qingzhu.qingzhushop.entity.Seckill;
import cn.edu.zstu.qingzhu.qingzhushop.mapper.SeckillMapper;
import cn.edu.zstu.qingzhu.qingzhushop.service.ISeckillDetailService;
import cn.edu.zstu.qingzhu.qingzhushop.service.ISeckillService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * FileName: SeckillServiceImpl
 *
 * @Author: LvYibin
 * @Date: 2021/5/17 09:07
 * @Description:
 */
@Service
public class SeckillServiceImpl extends ServiceImpl<SeckillMapper, Seckill> implements ISeckillService {

    private static final Logger log = LoggerFactory.getLogger(SeckillServiceImpl.class);
    private static final String keyPrefix = "redis:seckill:item:";

    @Autowired
    private ISeckillDetailService seckillDetailService;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public String handout(Seckill seckill) throws Exception {
        if (seckill.getTotal()>0&&seckill.getIsActive()!=null){
            String timestamp = String.valueOf(System.nanoTime());
            String killId = new StringBuilder(keyPrefix).append(timestamp).toString();
            seckill.setOnlyseckill(killId);
            String redTotalKey = killId + ":total";
            String redStatusKey = killId + ":status";
            redisTemplate.opsForValue().set(redTotalKey,seckill.getTotal(),10L, TimeUnit.MINUTES);
            redisTemplate.opsForValue().set(redStatusKey,seckill.getIsActive(),10L, TimeUnit.MINUTES);
            //异步储存秒杀
            int i = seckillDetailService.saveSeckill(seckill);
            if (i==1){
                return killId;
            }
            else {
                throw new Exception("系统异常-发布秒杀-参数不合法");
            }
        }else {
            throw new Exception("系统异常-发布秒杀-参数不合法");
        }
    }
//1成功 2没了 3抢过 0没开始或结束
    @Override
    public int rob(Integer userId, String killId) throws Exception {

        ValueOperations valueOperations = redisTemplate.opsForValue();
        Object total =  valueOperations.get(killId+ ":status");
        if (Integer.valueOf(total.toString())==Integer.valueOf(0)){
            return 0;
        }
//判断用户是否已经抢过
        Object obj = valueOperations.get(killId+":"+userId+":rob");
        //抢过，返回金额
        if (obj!=null){
            return 3;
        }

        final String lockKey = killId + "-lock";
        ValueOperations stringvalueOperations =  stringRedisTemplate.opsForValue();
        String value = System.nanoTime()+""+ UUID.randomUUID();
        Boolean lock = stringvalueOperations.setIfAbsent(lockKey,value);

        if(lock){
            stringRedisTemplate.expire(lockKey,2L,TimeUnit.SECONDS);
            try {
                if(click(killId)){
                    String redTotalKey = killId + ":total";
                    Integer currTotal = valueOperations.get(redTotalKey)!=null?(Integer) valueOperations.get(redTotalKey):0;
                    System.out.println("currTotal: "+(currTotal-1));
                    valueOperations.set(redTotalKey,currTotal-1);
                    seckillDetailService.saveSeckillDetail(userId,killId);
                    valueOperations.set(killId+":" + userId + ":rob",1,10L,TimeUnit.MINUTES);
                    log.info("当前用户抢到了物品：userId={},key={} ",userId,killId);
                    return 1;
                }else{
                    return 2;
                }
            }catch (Exception e){
                throw new Exception("系统异常-抢购-加分布式锁失败");
            }finally {
                if (value.equals(stringvalueOperations.get(lockKey).toString())){
                    stringRedisTemplate.delete(lockKey);
                }
            }
        }

        return 2;
    }






    public Boolean click(String redId) throws Exception{
        ValueOperations valueOperations = redisTemplate.opsForValue();
        String redTotalKey = redId + ":total";
        Object total = valueOperations.get(redTotalKey);
        if (total!=null && Integer.valueOf(total.toString())>0){
            return true;
        }
        return false;
    }
}
